package com.revzone.demo001.LogModule.aspect;

import com.alibaba.fastjson.JSONObject;
import com.revzone.demo001.LogModule.mapper.AccessLogsMapper;
import com.revzone.demo001.LogModule.mapper.ActionLogsMapper;
import com.revzone.demo001.entity.ExciptionEntity.AppException;
import com.revzone.demo001.entity.LogEntity.AccessLogs;
import com.revzone.demo001.entity.OtherEntity.R;
import com.revzone.demo001.entity.PermissionEntity.User;
import com.revzone.demo001.enums.ExciptionEnums.EnumExciption;
import com.revzone.demo001.utils.JwtUtils.JWTUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

@Aspect
@Component
@Order(1)
public class LogAspect {

    @Autowired
    private AccessLogsMapper accessLogsMapper; // 引入访问日志数据访问对象

    @Autowired
    private ActionLogsMapper actionLogsMapper;// 引入操作日志数据访问对象 //参数，请求类型，状态码

    @Autowired
    private HttpServletRequest request;// 引入HttpServletRequest对象，用于获取请求相关信息

    // 定义切点，用于匹配被@OperationLog注解修饰的方法
    @Pointcut(value = "@annotation(com.revzone.demo001.LogModule.aspect.OperationLog)")
    public void pointcut() {
    }

    /**
     * 在方法执行返回结果后执行 记录用户访问日志
     * @param joinPoint 切点对象，用于获取请求相关信息
     * @param ret 返回结果
     */
    @AfterReturning(pointcut = "pointcut()", returning = "ret")
    public void logAccess(JoinPoint joinPoint, Object ret) {
        // 获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取被调用的类名
        String className = joinPoint.getTarget().getClass().getName();
        //操作用户名
        String username = this.getRequestUserName(joinPoint,ret);

        // 创建访问日志对象
        AccessLogs accessLogs = new AccessLogs();
        accessLogs.setUrl(request.getRequestURI()); // 设置请求路径
        accessLogs.setMethod(request.getMethod()); // 设置请求方法
        accessLogs.setIp(request.getHeader("X-Real-IP")); // 设置客户端 IP 地址
        accessLogs.setAccessDate(new Date()); // 设置访问时间
        accessLogs.setAccessName(username);//设置访问操作人
        accessLogs.setClassName(className);//类名
        accessLogs.setMethodName(methodName);//方法名
        accessLogs.setAccessType(this.getRequestOperator(joinPoint).get(0));
        accessLogs.setRemarks(this.getRequestOperator(joinPoint).get(1));//方法备注
        accessLogs.setResult("success");
        accessLogs.setCode("200");
        // 将访问日志插入到数据库中
        accessLogsMapper.insert(accessLogs);
    }

    /**
     * 在方法执行抛出异常后执行
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(pointcut = "pointcut()", throwing = "ex")
    public void logAccess(JoinPoint joinPoint, Exception ex) {
        // 获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取被调用的类名
        String className = joinPoint.getTarget().getClass().getName();
        //操作用户名
        String username = this.getRequestUserName2(joinPoint);

        // 创建访问日志对象
        AccessLogs accessLogs = new AccessLogs();
        accessLogs.setUrl(request.getRequestURI()); // 设置请求路径
        accessLogs.setMethod(request.getMethod()); // 设置请求方法
        accessLogs.setIp(request.getHeader("X-Real-IP")); // 设置客户端 IP 地址
        accessLogs.setAccessDate(new Date()); // 设置访问时间
        accessLogs.setAccessName(username);//设置访问操作人
        accessLogs.setClassName(className);//类名
        accessLogs.setMethodName(methodName);//方法名
        accessLogs.setAccessType(this.getRequestOperator(joinPoint).get(0));
        accessLogs.setRemarks(this.getRequestOperator(joinPoint).get(1));//方法备注
        // 设置响应信息
        if(ex instanceof AppException){
            AppException appException = (AppException) ex;
            R.error(appException.getCode(),appException.getMsg());
            accessLogs.setResult(appException.getMsg());
            accessLogs.setCode(String.valueOf(appException.getCode()));
        }else {
            accessLogs.setResult(ex.getMessage());
            accessLogs.setCode(String.valueOf(EnumExciption.SYSTEM_ERROR.getCode()));
        }

        // 将访问日志插入到数据库中
        accessLogsMapper.insert(accessLogs);
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap(); // 获取请求参数
        JSONObject jsonObject = new JSONObject();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            // 将请求参数转换成 JSON 格式字符串
            jsonObject.put(entry.getKey(), entry.getValue());
        }
        return jsonObject.toJSONString();
    }

    private ArrayList<String> getRequestOperator(JoinPoint joinPoint) {
        // 获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();

        // 获取目标方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        // 获取方法上的@OperationLog注解对象
        OperationLog annotation = method.getAnnotation(OperationLog.class);

        // 处理注解信息
        if (annotation != null) {
            ArrayList<String> list = new ArrayList<>();
            list.add(annotation.value());
            list.add(annotation.description());
            return list;
        } else {
            ArrayList<String> list = new ArrayList<>();
            list.add("***");
            list.add("***");
            return list;
        }
    }

    private String getRequestUserName(JoinPoint joinPoint,Object ret){
        // 获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取被调用的类名
        String className = joinPoint.getTarget().getClass().getName();
        if(className.equals("com.revzone.demo001.service.impl.UserServiceImpl") && methodName.equals("getReUser")){
            // 设置响应信息
            if (ret instanceof R) {
                R r = (R) ret;
                User user = (User) r.get("info");//方法参数
                return user.getUserName();
            }else {
                return "DL";
            }
        }else {
            // 获取当前登录用户的信息
            Subject subject = SecurityUtils.getSubject();
            String token = (String) subject.getPrincipal();
            if (token != null) {
                return JWTUtil.getUsername(token);
            } else return "token异常访问";
        }
    }

    private String getRequestUserName2(JoinPoint joinPoint){
        // 获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取被调用的类名
        String className = joinPoint.getTarget().getClass().getName();
        if(className.equals("com.revzone.demo001.service.impl.UserServiceImpl") && methodName.equals("getReUser")){
            // 设置响应信息
            return "请先登录！";
        }else {
            // 获取当前登录用户的信息
            Subject subject = SecurityUtils.getSubject();
            String token = (String) subject.getPrincipal();
            if (token != null) {
                return JWTUtil.getUsername(token);
            } else return "token异常访问";

        }
    }

}
